#include "stdafx.h"

#include "EntityFactory.h"
#include "BasicTower.h"
#include "N64.h"
#include "Enemy.h"
#include "EnemySpawner.h"
#include "Projectile.h"
#include "Wall.h"
#include "EnemyProjectile.h"
#include "SlowTower.h"
#include "SlowProjectile.h"
#include "BasicTree.h"

#include "RenderObject.h"

#include "RenderSystem.h"
#include "ResourceManager.h"
#include "SceneManager.h"
#include "EntityManager.h"
#include "CollisionManager.h"
#include "Collider.h"
#include "TargetMediator.h"
#include "AttackWallMediator.h"

EntityFactory::EntityFactory(RenderSystem* render_system, ResourceManager* resource_manager, SceneManager* scene_manager)
	: m_render_system(render_system), m_resource_manager(resource_manager), m_scene_manager(scene_manager), m_collision_manager(nullptr), m_entity_manager(nullptr), m_target_mediator(nullptr), m_attack_wall_mediator(nullptr)
{
	m_shader = m_resource_manager->GetShader("vertexshader.hlsl", "pixelshader.hlsl");

	int vs_s[]={sizeof(OncePerFrame), sizeof(OncePerObject)};
	int ps_s[]={sizeof(DirectionalLight)};
	m_shader->AllocateVSConstants(2,vs_s);
	m_shader->AllocatePSConstants(1,ps_s);
	render_system->CreateConstantBuffers(m_shader);

	Sampler sampler;
	render_system->CreateSamplerState(&sampler,AM_WRAP,AM_WRAP,AM_WRAP,FM_LINEAR,CM_NEVER);
	m_shader->AllocateSamplers(1);
	m_shader->SetSampler(0,sampler);

	D3D10_INPUT_ELEMENT_DESC desc[]={
		{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D10_INPUT_PER_VERTEX_DATA,0},
		{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,12,D3D10_INPUT_PER_VERTEX_DATA,0},
		{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,20,D3D10_INPUT_PER_VERTEX_DATA,0}
	};

	render_system->CreateInputLayout(m_shader,desc,3);
	/*m_target_mediator = new TargetMediator;
	m_attack_wall_mediator = new AttackWallMediator;*/
}


EntityFactory::~EntityFactory(void){
	RemoveMediators();
}

Entity* EntityFactory::Create(EEntityType entity_type, Grid* grid)
{
	Entity* entity;
	SceneObject* scene_object;

	switch (entity_type)
	{
	case EEntityType::N64_Logo:
		{
			entity = new N64(entity_type);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("selector_texture.tga"), 
				m_shader, 
				m_resource_manager->GetModel("selector.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.0f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Basic_Tower:
		{
			entity = new BasicTower(entity_type, this, m_entity_manager, m_target_mediator);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("n64_texture.tga"), 
				m_shader, 
				m_resource_manager->GetModel("Tower.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.0f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			ScanCollider* scan_collider = new ScanCollider(m_collision_manager, 10.0f);
			static_cast<BasicTower*>(entity)->SetScanCollider(scan_collider);
			scan_collider->SetUserData(entity);
			m_collision_manager->AddCollider(scan_collider);
			break;
		}
	case EEntityType::Enemy_Type:
		{
			entity = new Enemy(entity_type, m_target_mediator, m_attack_wall_mediator, this, m_entity_manager);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("n64_texture.tga"), 
				m_shader, 
				m_resource_manager->GetModel("n64.obj")
				);
			entity->SetRotation(Vector3(0.0f, Math::ToRad(180.0f), 0.0f));
			Collider* collider = new BoxCollider(m_collision_manager, 1.5f, 5.0f, 1.5f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Enemy_Spawner:
		{
			entity = new EnemySpawner(entity_type, this, m_entity_manager);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("flame.tga"), 
				m_shader, 
				m_resource_manager->GetModel("selector.obj")
				);
			break;
		}

	case EEntityType::Projectile_Type:
		{
			entity = new Projectile(entity_type);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("projectile_normal.tga"), 
				m_shader, 
				m_resource_manager->GetModel("projectile_normal.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.5f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Enemy_Projectile:
		{
			entity = new EnemyProjectile(entity_type);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("projectile_normal.tga"), 
				m_shader, 
				m_resource_manager->GetModel("projectile_normal.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.5f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Wall_Type:
		{
			entity = new Wall(entity_type, m_attack_wall_mediator);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("n64_texture.tga"), 
				m_shader, 
				m_resource_manager->GetModel("wall_test.obj")
				);
			Collider* collider = new BoxCollider(m_collision_manager, 4.5f, 3.0f, 1.0f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Slow_Tower:
		{
			entity = new SlowTower(entity_type, this, m_entity_manager, m_target_mediator);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("slowing_tower.tga"), 
				m_shader, 
				m_resource_manager->GetModel("slowing_tower.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.0f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			ScanCollider* scan_collider = new ScanCollider(m_collision_manager, 10.0f);
			static_cast<SlowTower*>(entity)->SetScanCollider(scan_collider);
			scan_collider->SetUserData(entity);
			m_collision_manager->AddCollider(scan_collider);
			break;
		}
	case EEntityType::Slow_Projectile:
		{
			entity = new SlowProjectile(entity_type);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system, 
				m_resource_manager->GetTexture("n64_texture.tga"), 
				m_shader, 
				m_resource_manager->GetModel("projectile_normal.obj")
				);
			Collider* collider = new SphereCollider(m_collision_manager, 1.5f);
			entity->SetCollider(collider);
			collider->SetUserData(entity);
			m_collision_manager->AddCollider(collider);
			break;
		}
	case EEntityType::Tree:
		{
			entity = new BasicTree(entity_type);
			entity->m_render_object = new RenderObject;

			entity->m_render_object->Create(
				m_render_system,
				m_resource_manager->GetTexture("tree_texture.tga"),
				m_shader,
				m_resource_manager->GetModel("tree.obj")
				);
			break;
		}
		// Add more cases for different entities
	};

	scene_object = m_scene_manager->Create(entity->m_render_object->GetShader(), entity->m_render_object->GetTexture(), entity->m_render_object->GetRenderable());
	scene_object->m_material.m_states.m_depth = entity->m_render_object->GetDepthState();
	scene_object->m_material.m_states.m_rasterizer = entity->m_render_object->GetRasterizerState();

	entity->Init(scene_object, grid);

	entity->SetEntityListener(m_entity_manager);

	return entity;
}

void EntityFactory::CreateMediators()
{
	if (m_attack_wall_mediator == nullptr)
		m_attack_wall_mediator = new AttackWallMediator;
	if (m_target_mediator == nullptr)
		m_target_mediator = new TargetMediator;
}

void EntityFactory::RemoveMediators()
{
	if (m_target_mediator){
		delete m_target_mediator;
		m_target_mediator = nullptr;
	}

	if (m_attack_wall_mediator){
		delete m_attack_wall_mediator;
		m_attack_wall_mediator = nullptr;
	}
}